package org.example.netty.test.nio.netty;

import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageCodec;
import lombok.extern.slf4j.Slf4j;
import org.example.netty.test.nio.bean.LogMessage;
import org.example.netty.test.nio.bean.Message;
import org.example.netty.test.nio.util.SerializeUtils;

import java.util.Arrays;
import java.util.List;

/**
 * @author zp
 * @version 1.0
 * @description: 自定义的消息解码器
 * * +---------------------------------------------------------------+
 *  * | 魔数 2byte | 协议版本号 1byte | 序列化算法 1byte | 报文类型 1byte  |
 *  * +---------------------------------------------------------------+
 *  * | 状态 1byte |      数据长度 4byte     |         数据内容 （长度不定）
 *  * +---------------------------------------------------------------+
 * 原本不存在状态保存的Handler 可以使用注解标注为单例实现 但是ByteToMessageCodec 上面有判断 @Sharable的方法
 * 他的子类不允许使用 @Sharable 标注为单例的Handler 如果需要实现单例 可以实现 MessageToMessageCodec的编解码方法
 * 然后标注@Sharable 注解 使Handler是一个单例的实现
 *
 * 在使用的过程中 需要结合LengthFieldBasedFrameDecoder 编解码器 防止出现粘包和半包的问题 不然会出现数据读取异常
 * 和数据解码不准确的问题 如果可以最好也设置字符集编码 防止乱码的出现
 * @date 2023/3/30 19:40
 */
@Slf4j
public class MyAgreeOnMessageCodec extends ByteToMessageCodec<Message>{
    /**
     * @description: 编码 把一个对象编码成一个byte数组
     * @author zp
     * @date: 2023/3/30 20:02
     * @param ctx
     * @param msg
     * @param out
     */
    @Override
    protected void encode(ChannelHandlerContext ctx, Message msg, ByteBuf out) throws Exception {
        // 写入两个字节的魔数
        out.writeBytes(msg.getMagicNumber());
        // 协议版本号 一个字节
        out.writeBytes(msg.getVersion());
        // 序列化协议 一个字节
        out.writeBytes(msg.getSerializationAlgorithm());
        // 消息类型 一个字节
        out.writeBytes(msg.messageType());
        // 消息状态 一个字节
        out.writeBytes(msg.messageTypeStatus());
        // 获取使用JDK 序列化之后字节
        byte[] data = SerializeUtils.serialize(msg);
        // 写入四个字节的消息长度
        out.writeInt(data.length);
        // 写入消息
        out.writeBytes(data);
    }

    @Override
    protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
        // 获取魔数
        byte[] magicNumber = new byte[2];
        in.readBytes(magicNumber);
        // 获取版本号
        byte version = in.readByte();
        // 获取序列化类型
        byte serializationAlgorithm = in.readByte();
        // 获取消息类型
        byte messageType = in.readByte();
        // 获取状态
        byte status = in.readByte();
        // 获取消息长度
        int length = in.readInt();
        byte[] messageBytes = new byte[length];
        in.readBytes(messageBytes);

        LogMessage logMessage = SerializeUtils.deserialize(messageBytes,LogMessage.class);

        log.info("收到消息:{}", logMessage);
        log.info("{},{},{},{},{},{}", Arrays.toString(magicNumber),version,serializationAlgorithm,messageType,status,length);
    }
}
